﻿using System;
using System.Runtime.InteropServices;

using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using System.Web;
using Microsoft.SharePoint.Security;
using System.Security.Permissions;
using System.Web.UI.WebControls;
using Microsoft.SharePoint.Utilities;
using System.Web.UI;
using System.Text;
using System.Data;
using System.Globalization;
using System.Collections.Generic;
using System.IO;
using System.Collections;

namespace Yappi.HierarchicalField
{
    /// <summary>
    /// Контрол для отображения наших данных.
    /// </summary>
    [
    SharePointPermission(SecurityAction.LinkDemand, ObjectModel = true),
    AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal),
    SharePointPermission(SecurityAction.InheritanceDemand, ObjectModel = true),
    AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal),    
    CLSCompliant(false),
    Guid("a3225740-5572-4df2-86ef-8c566c67d4bb")]
    public class HierarchicalFieldFieldControl : BaseFieldControl
    {
        // Fields
        private DataView m_dataSource;
        private Image m_dropImage;
        private DropDownList m_dropList;
        private bool m_hasValueSet;
        private List<int> m_ids;
        private int m_selectedValueIndex = -1;
        private TextBox m_tbx;
        private object m_value;
        private SPWeb m_webForeign;


        private int[] validIds = new int[] { };
        /// <summary>
        /// Допустимые значения идентификаторов элементов
        /// </summary>
        public int[] ValidIds
        {
            get { return validIds; }
            set { validIds = value; }
        }

        private bool useFiltering = false;
        /// <summary>
        /// Использовать фильтрацию
        /// </summary>
        public bool UseFiltering
        {
            get { return useFiltering; }
            set { useFiltering = value; }
        }

        private string sortFieldName = string.Empty;
        /// <summary>
        /// Поле сортировки
        /// </summary>
        public string SortFieldName
        {
            get { return sortFieldName; }
            set { sortFieldName = value; }
        }

        // Methods
        private void Clear()
        {
            this.m_ids = null;
            this.m_dataSource = null;
            this.m_selectedValueIndex = -1;
        }

        [SharePointPermission(SecurityAction.Demand, ObjectModel = true), AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
        protected override void CreateChildControls()
        {
            if (!base.IsFieldValueCached)
            {
                if (base.Field == null)
                {
                    return;
                }
                base.CreateChildControls();
                if (base.ControlMode == SPControlMode.Display)
                {
                    return;
                }
                SPFieldLookup field = (SPFieldLookup)base.Field;
                HierarchicalField fl = (HierarchicalField)base.Field;
                if (field.AllowMultipleValues)
                {
                    return;
                }
                this.Controls.Clear();
                if ((((this.DataSource != null) && (this.DataSource.Count > 20)) && (!base.InDesign)))
                {
                    this.m_tbx = new TextBox();
                    this.m_tbx.Attributes.Add("choices", this.Choices);
                    this.m_tbx.Attributes.Add("match", "");
                    this.m_tbx.Attributes.Add("onkeydown", "HandleKey()");
                    this.m_tbx.Attributes.Add("onkeypress", "HandleChar()");
                    this.m_tbx.Attributes.Add("onfocusout", "HandleLoseFocus()");
                    this.m_tbx.Attributes.Add("onchange", "HandleChange()");
                    this.m_tbx.Attributes.Add("class", "ms-lookuptypeintextbox");
                    this.m_tbx.Attributes.Add("title", field.Title);
                    this.m_tbx.TabIndex = this.TabIndex;
                    this.m_tbx.Attributes["optHid"] = this.HiddenFieldName;
                    Literal child = new Literal();
                    child.Text = "<span style=\"vertical-align:middle\">";
                    Literal literal2 = new Literal();
                    literal2.Text = "</span>";
                    this.Controls.Add(child);
                    this.Controls.Add(this.m_tbx);
                    this.m_tbx.Attributes.Add("opt", "_Select");
                    this.m_dropImage = new Image();
                    this.m_dropImage.ImageUrl = "/_layouts/images/dropdown.gif";
                    this.m_dropImage.Attributes.Add("alt", SPResource.GetString("LookupWordWheelDropdownAlt", new object[0]));
                    this.m_dropImage.Attributes.Add("style", "vertical-align:middle;");
                    this.Controls.Add(this.m_dropImage);

                    this.Controls.Add(literal2);
                }
                else
                {
                    this.m_dropList = new DropDownList();
                    this.m_dropList.ID = "Lookup";
                    this.m_dropList.TabIndex = this.TabIndex;
                    this.m_dropList.DataSource = this.DataSource;
                    this.m_dropList.DataValueField = "ValueField";
                    this.m_dropList.DataTextField = "TextField";
                    this.m_dropList.ToolTip = SPHttpUtility.NoEncode(field.Title);
                    this.m_dropList.DataBind();
                    this.Controls.Add(this.m_dropList);
                    Literal javaScript = new Literal();
                    this.Controls.Add(javaScript);
                    try
                    {
                        if (bool.Parse(fl.JavaScriptPlacer))
                            javaScript.Text = string.Format(@"<script type=""text/javascript"" src=""/_layouts/hierarhyCreator.js"">
</script>
<script type=""text/javascript"">
ApplyToStyle(FindPopup(""{0}""));                        
</script>
", field.InternalName);
                    }
                    catch (FormatException) { }
                }
            }
            else
            {
                base.CreateChildControls();
                return;
            }
            if (this.m_webForeign != null)
            {
                this.m_webForeign.Close();
                this.m_webForeign = null;
            }
            this.Controls.Add(new LiteralControl("<br/>"));
            this.SetFieldControlValue(this.ItemFieldValue);
        }

        [SharePointPermission(SecurityAction.Demand, ObjectModel = true)]
        public override void Focus()
        {
            if (!base.InDesign)
            {
                this.EnsureChildControls();
                if (this.m_tbx == null)
                {
                    if (this.m_dropList != null)
                    {
                        this.m_dropList.Focus();
                    }
                }
                else
                {
                    this.m_tbx.Focus();
                }
            }
        }

        [SharePointPermission(SecurityAction.Demand, ObjectModel = true)]
        protected override void OnInit(EventArgs e)
        {
            base.CanCacheRenderedFieldValue = false;
            base.OnInit(e);
        }

        [SharePointPermission(SecurityAction.Assert, ObjectModel = true), AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal), SharePointPermission(SecurityAction.Demand, ObjectModel = true), AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            if (this.m_dropImage != null)
            {
                this.m_dropImage.Attributes.Add("onclick", "ShowDropdown('" + this.m_tbx.ClientID + "');");
            }
        }

        //private void SetFieldControlValue(object value)
        //{
        //    if ((this.m_value != value) || !this.m_hasValueSet)
        //    {
        //        if (ControlMode != SPControlMode.Edit)
        //           this.Clear();
        //        this.m_value = value;
        //        this.m_hasValueSet = true;
        //        if (this.DataSource != null)
        //        {
        //            if (this.m_dropList != null)
        //            {
        //                if (this.m_selectedValueIndex >= 0)
        //                {
        //                    this.m_dropList.SelectedIndex = this.m_selectedValueIndex;
        //                }
        //                else
        //                {
        //                    this.m_dropList.SelectedIndex = -1;
        //                }
        //            }
        //            else if (this.m_tbx != null)
        //            {
        //                DataRowView view = null;
        //                if (this.m_selectedValueIndex >= 0)
        //                {
        //                    view = this.m_dataSource[this.m_selectedValueIndex];
        //                    this.m_tbx.Text = view["TextField"] as string;
        //                }
        //                if (this.Page != null)
        //                {
        //                    string str = "0";
        //                    if (this.m_selectedValueIndex < 0)
        //                    {
        //                        if (this.Page.IsPostBack)
        //                        {
        //                            str = this.Context.Request.Form[this.HiddenFieldName];
        //                            if (string.IsNullOrEmpty(str))
        //                            {
        //                                str = "0";
        //                            }
        //                        }
        //                    }
        //                    else
        //                    {
        //                        view = this.m_dataSource[this.m_selectedValueIndex];
        //                        str = ((int)view["ValueField"]).ToString(CultureInfo.InvariantCulture);
        //                    }
        //                    this.Page.ClientScript.RegisterHiddenField(this.HiddenFieldName, str);
        //                }
        //            }
        //        }
        //    }
        //}

        private void SetFieldControlValue(object value)
        {
            if ((this.m_value != value) || !this.m_hasValueSet)
            {
                this.Clear();
                this.m_value = value;
                this.m_hasValueSet = true;
                if (this.DataSource != null)
                {
                    if (this.m_dropList != null)
                    {
                        if (this.m_selectedValueIndex >= 0)
                        {
                            this.m_dropList.SelectedIndex = this.m_selectedValueIndex;
                        }
                        else
                        {
                            this.m_dropList.SelectedIndex = -1;
                        }
                    }
                    else if (this.m_tbx != null)
                    {
                        DataRowView view = null;
                        if (this.m_selectedValueIndex >= 0)
                        {
                            view = this.m_dataSource[this.m_selectedValueIndex];
                            this.m_tbx.Text = view["TextField"] as string;
                        }
                        if (this.Page != null)
                        {
                            string str = "0";
                            if (this.m_selectedValueIndex < 0)
                            {
                                if (this.Page.IsPostBack)
                                {
                                    str = this.Context.Request.Form[this.HiddenFieldName];
                                    if (string.IsNullOrEmpty(str))
                                    {
                                        str = "0";
                                    }
                                }
                            }
                            else
                            {
                                view = this.m_dataSource[this.m_selectedValueIndex];
                                str = ((int)view["ValueField"]).ToString(CultureInfo.InvariantCulture);
                            }
                            this.Page.ClientScript.RegisterHiddenField(this.HiddenFieldName, str);
                        }
                    }
                }
            }
        }



        [SharePointPermission(SecurityAction.Demand, ObjectModel = true)]
        public override void Validate()
        {
            if (((base.ControlMode != SPControlMode.Display) && base.IsValid) && (this.m_tbx != null))
            {
                base.Validate();
                int num = (int)this.Value;
                if (num <= 0)
                {
                    if (base.Field.Required && (this.m_tbx.Text.Length == 0))
                    {
                        base.IsValid = false;
                        base.ErrorMessage = SPResource.GetString("MissingRequiredField", new object[0]);
                    }
                    else if (this.m_tbx.Text.Length > 0)
                    {
                        base.IsValid = false;
                        base.ErrorMessage = SPResource.GetString("InvalidLookupChoice", new object[0]);
                    }
                }
            }
        }

        // Properties
        private string Choices
        {
            get
            {
                StringBuilder builder = new StringBuilder();
                bool flag = true;

                foreach (DataRowView current in this.DataSource)
                {
                    string textField = (current["TextField"] as string).Replace("|", "||");

                    if (!flag)
                    {
                        builder.AppendFormat("|{0}", textField);
                        builder.AppendFormat("|{0}", current["ValueField"]);
                    }
                    else
                    {
                        builder.Append(textField);
                        flag = false;
                        builder.AppendFormat("|{0}", current["ValueField"]);
                    }

                }
                return builder.ToString();
            }
        }

        private string lookupFullName = string.Empty;

        /// <summary>
        /// Длинное имя в списке
        /// </summary>
        public string LookupFullName
        {
            get { return lookupFullName; }
            set { lookupFullName = value; }
        }

        internal ICollection DataSource
        {
            get
            {
                string lookupField;
                int selectedItemId;

                if (this.m_dataSource != null)
                    return m_dataSource;

                int selectedItemIndex = 0;
                SPFieldLookup lookup = (SPFieldLookup)base.Field;
                if (lookup != null)
                {
                    lookupField = LookupFullName;
                    if (string.IsNullOrEmpty(lookupField))
                    {
                        lookupField = lookup.LookupField;
                        if (string.IsNullOrEmpty(lookupField))
                        {
                            lookupField = "Title"; //TODO: проверить правильность
                        }
                    }
                }
                else
                {
                    return null;
                }

                if (this.ItemIds.Count <= 0)
                {
                    selectedItemId = 0;
                }
                else
                {
                    selectedItemId = this.ItemIds[0];
                }

                DataTable table = new DataTable();
                table.Locale = CultureInfo.InvariantCulture;
                table.Columns.Add(new DataColumn("ValueField", typeof(int)));
                table.Columns.Add(new DataColumn("TextField", typeof(string)));
                if (!lookup.Required && !lookup.AllowMultipleValues)
                {
                    DataRow row = table.NewRow();
                    row[0] = 0;
                    row[1] = SPResource.GetString("LookupFieldNoneOption", new object[0]);
                    table.Rows.Add(row);
                    selectedItemIndex++;
                }
                SPList lookupList = this.LookupList;
                if (lookupList != null)
                {
                    try
                    {
                        SPField field = lookupList.Fields.GetField(lookupField);
                        SPQuery query = new SPQuery();
                        query.ViewXml = GenerateQuery(lookupField);
                        SPListItemCollection items = lookupList.GetItems(query);
                        for (int i = 0; i < items.Count; i++)
                        {
                            string fieldValueAsText = field.GetFieldValueAsText(items[i][lookupField]);
                            if (!string.IsNullOrEmpty(fieldValueAsText) && (!UseFiltering || Array.IndexOf(ValidIds, items[i].ID) != -1))
                            {
                                DataRow newRow = table.NewRow();
                                newRow[0] = items[i].ID;
                                newRow[1] = fieldValueAsText;
                                table.Rows.Add(newRow);
                                if (((int)newRow[0]) == selectedItemId)
                                {
                                    this.m_selectedValueIndex = selectedItemIndex;
                                }
                                selectedItemIndex++;
                            }
                        }
                        this.m_dataSource = new DataView(table);
                        return m_dataSource;
                    }
                    catch (ArgumentException)
                    {
                        return null;
                    }
                }
                return null;
            }
        }

        protected virtual string GenerateQuery(string lookupField)
        {
            StringBuilder builder = new StringBuilder("<View Scope=\"RecursiveAll\"><Query><OrderBy><FieldRef Name=\"");
            builder.Append(!string.IsNullOrEmpty(SortFieldName) ? SortFieldName : lookupField);
            builder.Append("\"/></OrderBy></Query><ViewFields><FieldRef Name=\"");
            builder.Append(lookupField);
            builder.Append("\"/></ViewFields></View>");
            return builder.ToString();
        }

        private string HiddenFieldName
        {
            get
            {
                return ("SP" + base.Field.InternalName + "_Hidden");
            }
        }

        protected virtual IList<int> ItemIds
        {
            get
            {
                SPFieldLookupValue fieldLookupValue;
                int lookupId;
                if (this.m_ids != null)
                {
                    return this.m_ids;
                }
                else
                {
                    if (this.m_value != null)
                    {
                        if (!(this.m_value is SPFieldLookupValue))
                        {
                            if (!(this.m_value is string))
                            {
                                throw new ArgumentException();
                            }
                            else
                            {
                                try
                                {
                                    fieldLookupValue = new SPFieldLookupValue((string)this.m_value);
                                }
                                catch (ArgumentException)
                                {
                                    return new List<int>();
                                }
                            }
                        }
                        else
                        {
                            fieldLookupValue = (SPFieldLookupValue)this.m_value;
                        }
                    }
                    else
                        fieldLookupValue = new SPFieldLookupValue();

                    lookupId = fieldLookupValue.LookupId;
                    this.m_ids = new List<int>(1);
                    this.m_ids.Add(lookupId);
                    return this.m_ids;
                }
            }

        }

        private SPList LookupList
        {
            get
            {
                SPWeb webForeign;
                bool catchAccessDeniedException;
                SPFieldLookup field = (SPFieldLookup)base.Field;
                if (field.LookupList != "UserInfo")
                {
                    if (field.LookupList != "Docs")
                    {
                        if (field.LookupList == "Self")
                        {
                            return this.Web.Lists[base.ListId];
                        }
                        else
                        {
                            webForeign = this.Web;
                            catchAccessDeniedException = SPSecurity.CatchAccessDeniedException;
                            SPSecurity.CatchAccessDeniedException = false;
                            if (field.LookupWebId != this.Web.ID)
                            {
                                try
                                {
                                    this.m_webForeign = this.Web.Site.OpenWeb(field.LookupWebId);
                                    webForeign = this.m_webForeign;
                                }
                                catch (ArgumentException)
                                {
                                    webForeign = this.Web;
                                }
                                catch (FileNotFoundException)
                                {
                                    webForeign = this.Web;
                                }
                                catch (UnauthorizedAccessException)
                                {
                                    return null;
                                }
                                finally
                                {
                                    SPSecurity.CatchAccessDeniedException = catchAccessDeniedException;
                                }
                                //return null;
                            }
                        }
                    }
                    else
                    {
                        return null;
                    }
                }
                else
                {
                    return this.Web.SiteUserInfoList;
                }

                SPSecurity.CatchAccessDeniedException = false;
                try
                {
                    return webForeign.Lists[new Guid(field.LookupList)];
                }
                catch (UnauthorizedAccessException)
                {
                    return null;
                }
                catch (SPException)
                {
                    return null;
                }
                finally
                {
                    SPSecurity.CatchAccessDeniedException = catchAccessDeniedException;
                }
            }
        }

        public override object Value
        {
            get
            {
                EnsureChildControls();


                string svalue = Page.Request.Form[HiddenFieldName];
                if (!string.IsNullOrEmpty(svalue))
                {
                    int result = int.Parse(svalue);
                    return result;
                }
                else
                {
                    return m_dropList.SelectedValue;
                }
            }
            set
            {
                this.EnsureChildControls();
                this.SetFieldControlValue(value);
            }
        }
    }
}
